home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1996 February / EnigmA AMIGA RUN 04 (1996)(G.R. Edizioni)(IT)[!][issue 1996-02][Skylink CD III].iso / earcd / midi / midifl12.lha / midifile.new / mf1to0.c < prev    next >
C/C++ Source or Header  |  1995-08-27  |  17KB  |  735 lines

  1. /*
  2.  * f1to0.c 4/30/89
  3.  *
  4.  * Author:  Michael S. Czeiszperger
  5.  * Purpose: The program converts format 1 MIDI files to format 0
  6.  *          MIDI files.  It is meant to demonstrate the use of
  7.  *          the midifile library.  The internal data format is
  8.  *          a linked list of MIDI and SMF meta events.
  9.  *
  10.  *          The spec is available from:
  11.  *               International MIDI Association
  12.  *               5316 West 57th Street
  13.  *               Los Angeles, CA 90056
  14.  *
  15.  *          An in-depth description of the spec can also be found
  16.  *          in the article "Introducing Standard MIDI Files", published
  17.  *          in Electronic Musician magazine, April, 1988.
  18.  * 
  19.  * usage: f1to0 infile outfile
  20.  * 
  21.  */
  22.  
  23. char *_version = "$VER: mf1to0 V 1.00 (24-Jan-95)";
  24.  
  25. #include <stdio.h>
  26. #include <ctype.h>
  27.  
  28. #include <stdlib.h>
  29.  
  30. #include "midifile.h"
  31.  
  32. enum PACKET_TYPE
  33.   {
  34.     MIDI_EVENT, META_EVENT
  35.       };
  36.  
  37. struct MIDIpacket        /* Stucture for MIDI events */
  38.   {
  39.     enum PACKET_TYPE p_type;    /* What type of packet is it?               */
  40.     unsigned long time;        /* absolute time of event, in ms increments */
  41.     unsigned int m_type;    /* What kind of MIDI message?               */
  42.     unsigned int chan;        /* The MIDI channel                         */
  43.     unsigned long len;        /* length of the midi message               */
  44.     unsigned char *data;    /* pointer to the data                      */
  45.     struct MIDIpacket *next, *before;    /* point to next packet */
  46.       }
  47.  *sequence_start, *sequence_end;
  48.  
  49. /* 
  50. This example structure is not very portable. It does, however,
  51. mirror the logical operation of the header, and on some machines can
  52. be written and read directly.  It assumes that shorts are at least
  53. two bytes and chars are at least one byte.
  54.  */
  55. struct header_type
  56.   {
  57.     short format;
  58.     short ntrks;
  59.     union
  60.     {
  61.         short quarter_note;
  62.         struct
  63.           {
  64.             char format;
  65.             char resolution;
  66.               }
  67.         smpte;
  68.         }
  69.     division;
  70.       }
  71. header;
  72.  
  73. /* These lines are needed to use the library */
  74. FILE *fpIn, *fpOut;
  75. extern long Mf_currtime;
  76. /* mygetc : returns <int> with input variables:
  77.  * void:
  78.  */
  79. int mygetc (void)
  80. {
  81.   return (getc (fpIn));
  82. }
  83.  
  84. /* ------------------------------------------------------------------------ */
  85.  
  86. /* myputc : returns <int> with input variables:
  87.  * c:
  88.  */
  89. int myputc (char c)
  90. {
  91.   return (putc (c, fpOut));
  92. }
  93.  
  94. /* ------------------------------------------------------------------------ */
  95.  
  96. /* main : returns <int> with input variables:
  97.  * argc:
  98.  * argv:
  99.  */
  100. int main (
  101.   int argc,
  102.   char **argv)
  103. {
  104.   if (argc != 3) {
  105.  
  106.     printf ("Usage: mf1to0 <infile> <outfile>\n");
  107.     printf ("mf1to0 converts a MIDI format 1 file to MIDI format 0\n");
  108.     printf ("Original code by Michael S. Czeiszperger\n");
  109.     printf ("Amiga port by Andreas Jung (ajung@cs.uni-sb.de)\n");
  110.     printf ("Recompiled using the Dice Professional compiler\n");
  111.  
  112.     exit (0);
  113.     }
  114.  
  115.   if ((fpIn = fopen (argv[1], "r")) == 0L) {
  116.  
  117.     printf ("mf1to0: unable to open file '%s' for reading.\n", argv[1]);
  118.     exit (0);
  119.     }
  120.  
  121.   if ((fpOut = fopen (argv[2], "w")) == 0L) {
  122.  
  123.     printf ("mf1to0: unable to open file '%s' for writing.\n", argv[2]);
  124.     exit (0);
  125.     }
  126.  
  127.   init_funcs ();
  128.  
  129.   /* read the midi file */
  130.   mfread ();
  131.  
  132.   /* write a single track */
  133.   mfwrite ((int) header.format, 1, (int) header.division.quarter_note, fpOut);
  134. }
  135.  
  136. /* ------------------------------------------------------------------------ */
  137.  
  138. /* myheader : returns <int> with input variables:
  139.  * format:
  140.  * ntrks:
  141.  * division:
  142.  */
  143. int myheader (
  144.   int format,
  145.   int ntrks,
  146.   int division)
  147. {
  148.   header.format = format;
  149.   header.ntrks = ntrks;
  150.   header.division.quarter_note = division;
  151. }
  152.  
  153. /* ------------------------------------------------------------------------ */
  154.  
  155. /* myerror : returns <int> with input variables:
  156.  * s:
  157.  */
  158. int myerror (char *s)
  159. {
  160.   printf ("%10ld: %s\n", Mf_currtime, s);
  161. }
  162.  
  163. /* ------------------------------------------------------------------------ */
  164.  
  165. /*
  166.  * mywritetrack()
  167.  *
  168.  * Sample showing how to use the library routines to write out a track.
  169.  * Returns 1 if successful, and -1 if not.
  170.  *
  171.  */
  172. /* mywritetrack : returns <int> with input variables:
  173.  * track:
  174.  */
  175. int mywritetrack (int track)
  176. {
  177.   struct MIDIpacket *current;
  178.   unsigned long delta_time;
  179.  
  180.   current = sequence_start;    /* init to point at the beginning of the list */
  181.  
  182.   /* shuffle through each element in the linked list, writing out
  183. the data in the standard MIDI format */
  184.   while (current != 0L) {
  185.  
  186.     if (current == sequence_start)
  187.     delta_time = current->time;
  188.     else
  189.     delta_time = current->time - (current->before)->time;
  190. #ifdef DEBUG
  191.     printf ("ticks = %lu event = %d packet = %d chan = %d len = %lu\n",
  192.     current->time, current->m_type, current->p_type, current->chan, current->len);
  193. #endif
  194.  
  195.     if (current->p_type == MIDI_EVENT) {
  196.  
  197.           if (mf_write_midi_event (delta_time, current->m_type, current->chan, current->data, current->len) < 0)
  198.         return (-1);
  199.         }
  200.     else if (current->p_type == META_EVENT) {
  201.  
  202.           if (mf_write_meta_event (delta_time, current->m_type, current->data, current->len) < 0)
  203.         return (-1);
  204.         }
  205.     else
  206.     fprintf (stderr, "Unknown MIDI packet encounted.\n");
  207.  
  208.     current = current->next;
  209.     }
  210.   return (1);
  211. }
  212.  
  213. /* ------------------------------------------------------------------------ */
  214.  
  215. /* end of write_track() */
  216.  
  217. /*
  218.  * This routine adds a MIDI or META event into the linked list.  
  219.  */
  220. /* ticks:  absolute ticks of event
  221.  * event_type:  note_on, note_off, etc
  222.  * packet_type:  What kind of data?
  223.  * data:  already allocated data
  224.  * len:  length of data
  225.  */
  226. /* add_packet : returns <void> with input variables:
  227.  * ticks:
  228.  * event_type:
  229.  * packet_type:
  230.  * chan:
  231.  * data:
  232.  * len:
  233.  */
  234. void add_packet (
  235.   unsigned long ticks,
  236.   int event_type,
  237.   enum PACKET_TYPE packet_type,
  238.   int chan,
  239.   unsigned char *data,
  240.   unsigned long len)
  241. {
  242.   struct MIDIpacket *scratch, *insert_pt, *get_insert_point ();
  243.  
  244. #ifdef DEBUG
  245.   printf ("ticks = %d event = %d packet = %d chan = %d len = %d\n", ticks, event_type, packet_type, chan, len);
  246. #endif
  247.   scratch = (struct MIDIpacket *) malloc (sizeof (struct MIDIpacket));
  248.  
  249.   if (scratch == NULL) {
  250.  
  251.     fprintf (stderr, "Sorry, out of memory!\n");
  252.     exit (1);
  253.     }
  254.  
  255.   scratch->data = data;
  256.   scratch->m_type = event_type;
  257.   scratch->p_type = packet_type;
  258.   scratch->chan = chan;
  259.   scratch->len = len;
  260.   scratch->time = ticks;
  261.  
  262.   /* Where in the linked list should this packet go? */
  263.   insert_pt = get_insert_point (sequence_start, sequence_end, ticks);
  264.  
  265.   if (sequence_start == 0L) {    /* the list is empty */
  266.  
  267.     sequence_start = sequence_end = scratch;
  268.     scratch->before = 0L;
  269.     scratch->next = 0L;
  270.     }
  271.   else if (insert_pt == 0L) {    /* insert the new bottom record */
  272.  
  273.     sequence_end->next = scratch;
  274.     scratch->before = sequence_end;
  275.     scratch->next = 0L;
  276.     sequence_end = scratch;
  277.     }
  278.   else if (insert_pt == sequence_start) {        /* insert the new top record */
  279.  
  280.     sequence_start->before = scratch;
  281.     scratch->before = 0L;
  282.     scratch->next = sequence_start;
  283.     sequence_start = scratch;
  284.     }
  285.   else {
  286.     /* insert before the insert pointer */
  287.     scratch->next = insert_pt;
  288.     scratch->before = insert_pt->before;
  289.     insert_pt->before = scratch;
  290.     (scratch->before)->next = scratch;
  291.     }
  292. }
  293.  
  294. /* ------------------------------------------------------------------------ */
  295.  
  296. /* end of add_packet() */
  297. /*
  298.  * get_insert_point()
  299.  *    A routine to help insertion into a linked list,  
  300.  *    by returning a pointer to the position in the list
  301.  *    where the MIDI packet should be inserted based on
  302.  *    the time the MIDI event occurs. This could be a lot
  303.  *    faster, but was left simple for easy debugging.
  304.  *    If you'd like to speed this up, please go ahead!
  305.  */
  306. /* * get_insert_point : returns <struct MIDIpacket> with input variables:
  307.  * top:
  308.  * bottom:
  309.  * time:
  310.  */
  311. struct MIDIpacket * get_insert_point (
  312.   struct MIDIpacket *top,
  313.   struct MIDIpacket *bottom,
  314.   unsigned long time)
  315. {
  316.   struct MIDIpacket *index;
  317.   /* this keeps track of the last inset point, making it easier */
  318.   /* to find the next one assuming that most times will be     */
  319.   /* consecutive.                                               */
  320.   static struct MIDIpacket *insert_pointer;
  321.  
  322.   if (top == 0L || bottom == 0L)
  323. return (0L);
  324.   if (time > bottom->time)
  325. return (0L);        /* tack onto end of list */
  326.   if (time < top->time)
  327. return (top);        /* insert as the new first record */
  328.  
  329.   /* check around where the last packet was inserted */
  330.   if (insert_pointer != 0L)
  331. index = insert_pointer;
  332.   else {
  333.  
  334.     index = sequence_start;
  335.     insert_pointer = index;
  336.     }
  337.   if (time > index->time) {
  338.  
  339.     while (time > index->time && index != 0L)
  340.     index = index->next;
  341.     return (index);
  342.     }
  343.   else if (time < index->time) {
  344.  
  345.     while (time < index->time && index != 0L)
  346.     index = index->before;
  347.     return (index->next);
  348.     }
  349.   else
  350. return (insert_pointer);
  351. }
  352.  
  353. /* ------------------------------------------------------------------------ */
  354.  
  355. /* end of get_insert_point() */
  356. /* Routines called from midifile lib */
  357. /* mynoteon : returns <int> with input variables:
  358.  * chan:
  359.  * c1:
  360.  * c2:
  361.  */
  362. int mynoteon (
  363.   int chan,
  364.   int c1,
  365.   int c2)
  366. {
  367.   unsigned char *data;
  368.  
  369.   data = (unsigned char *) malloc (sizeof (char) * 2);
  370.   if (data == NULL) {
  371.  
  372.     fprintf (stderr, "Sorry, out of memory!\n");
  373.     exit (1);
  374.     }
  375.   data[0] = (unsigned char) c1;
  376.   data[1] = (unsigned char) c2;
  377.   add_packet ((unsigned long) Mf_currtime, note_on, MIDI_EVENT, chan, data, (unsigned long) 2);
  378. }
  379.  
  380. /* ------------------------------------------------------------------------ */
  381.  
  382. /* mynoteoff : returns <int> with input variables:
  383.  * chan:
  384.  * c1:
  385.  * c2:
  386.  */
  387. int mynoteoff (
  388.   int chan,
  389.   int c1,
  390.   int c2)
  391. {
  392.   unsigned char *data;
  393.  
  394.   data = (unsigned char *) malloc (sizeof (char) * 2);
  395.   if (data == NULL) {
  396.  
  397.     fprintf (stderr, "Sorry, out of memory!\n");
  398.     exit (1);
  399.     }
  400.   data[0] = (unsigned char) c1;
  401.   data[1] = (unsigned char) c2;
  402.   add_packet ((unsigned long) Mf_currtime, note_off, MIDI_EVENT, chan, data, (unsigned long) 2);
  403. }
  404.  
  405. /* ------------------------------------------------------------------------ */
  406.  
  407. /* mypressure : returns <int> with input variables:
  408.  * chan:
  409.  * pitch:
  410.  * pressure:
  411.  */
  412. int mypressure (
  413.   int chan,
  414.   int pitch,
  415.   int pressure)
  416. {
  417.   unsigned char *data;
  418.  
  419.   data = (unsigned char *) malloc (sizeof (char) * 2);
  420.   if (data == NULL) {
  421.  
  422.     fprintf (stderr, "Sorry, out of memory!\n");
  423.     exit (1);
  424.     }
  425.   data[0] = (unsigned char) pitch;
  426.   data[1] = (unsigned char) pressure;
  427.   add_packet ((unsigned long) Mf_currtime, poly_aftertouch, MIDI_EVENT, chan, data, (unsigned long) 2);
  428. }
  429.  
  430. /* ------------------------------------------------------------------------ */
  431.  
  432. /* mykeypressure : returns <int> with input variables:
  433.  * chan:
  434.  * pitch:
  435.  * pressure:
  436.  */
  437. int mykeypressure (
  438.   int chan,
  439.   int pitch,
  440.   int pressure)
  441. {
  442.   unsigned char *data;
  443.  
  444.   data = (unsigned char *) malloc (sizeof (char) * 2);
  445.   if (data == NULL) {
  446.  
  447.     fprintf (stderr, "Sorry, out of memory!\n");
  448.     exit (1);
  449.     }
  450.   data[0] = (unsigned char) pitch;
  451.   data[1] = (unsigned char) pressure;
  452.   add_packet ((unsigned long) Mf_currtime, channel_aftertouch, MIDI_EVENT, chan, data, (unsigned long) 2);
  453. }
  454.  
  455. /* ------------------------------------------------------------------------ */
  456.  
  457. /* myparameter : returns <int> with input variables:
  458.  * chan:
  459.  * control:
  460.  * value:
  461.  */
  462. int myparameter (
  463.   int chan,
  464.   int control,
  465.   int value)
  466. {
  467.   unsigned char *data;
  468.  
  469.   data = (unsigned char *) malloc (sizeof (char) * 2);
  470.   if (data == NULL) {
  471.  
  472.     fprintf (stderr, "Sorry, out of memory!\n");
  473.     exit (1);
  474.     }
  475.   data[0] = (unsigned char) control;
  476.   data[1] = (unsigned char) value;
  477.   add_packet ((unsigned long) Mf_currtime, control_change, MIDI_EVENT, chan, data, (unsigned long) 2);
  478. }
  479.  
  480. /* ------------------------------------------------------------------------ */
  481.  
  482. /* mytempo : returns <int> with input variables:
  483.  * microsecs:
  484.  */
  485. int mytempo (long microsecs)
  486. {
  487.   unsigned char *data;
  488.   data = (unsigned char *) malloc (sizeof (char) * 3);
  489.   if (data == NULL) {
  490.  
  491.     fprintf (stderr, "Sorry, out of memory!\n");
  492.     exit (1);
  493.     }
  494.   data[2] = (unsigned) (microsecs & 0xff);
  495.   data[1] = (unsigned) ((microsecs >> 8) & 0xff);
  496.   data[0] = (unsigned) ((microsecs >> 16) & 0xff);
  497.   add_packet ((unsigned long) Mf_currtime, set_tempo, META_EVENT, 0, data, (unsigned long) 3);
  498. }
  499.  
  500. /* ------------------------------------------------------------------------ */
  501.  
  502. /* myvarlen : returns <int> with input variables:
  503.  * type:
  504.  * len:
  505.  * msg:
  506.  */
  507. int myvarlen (
  508.   int type,
  509.   int len,
  510.   char *msg)
  511. {
  512.   unsigned char *data;
  513.   int i;
  514.  
  515.   data = (unsigned char *) malloc ((unsigned) (sizeof (char) * len));
  516.   if (data == NULL) {
  517.  
  518.     fprintf (stderr, "Sorry, out of memory!\n");
  519.     exit (1);
  520.     }
  521.   for (i = 0; i < len; i++)
  522. data[i] = msg[i];
  523.   add_packet ((unsigned long) Mf_currtime, type, META_EVENT, 0, data, (unsigned long) len);
  524. }
  525.  
  526. /* ------------------------------------------------------------------------ */
  527.  
  528. /* mysmpte : returns <int> with input variables:
  529.  * hour:
  530.  * min:
  531.  * sec:
  532.  * frame:
  533.  * fract:
  534.  */
  535. int mysmpte (
  536.   int hour,
  537.   int min,
  538.   int sec,
  539.   int frame,
  540.   int fract)
  541. {
  542.   unsigned char *data;
  543.  
  544.   data = (unsigned char *) malloc (sizeof (char) * 5);
  545.   if (data == NULL) {
  546.  
  547.     fprintf (stderr, "Sorry, out of memory!\n");
  548.     exit (1);
  549.     }
  550.   data[0] = hour;
  551.   data[1] = min;
  552.   data[2] = sec;
  553.   data[3] = frame;
  554.   data[4] = fract;
  555.   add_packet ((unsigned long) Mf_currtime, smpte_offset, META_EVENT, 0, data, (unsigned long) 5);
  556. }
  557.  
  558. /* ------------------------------------------------------------------------ */
  559.  
  560. /* myprogram : returns <int> with input variables:
  561.  * chan:
  562.  * program:
  563.  */
  564. int myprogram (
  565.   int chan,
  566.   int program)
  567. {
  568.   unsigned char *data;
  569.   data = (unsigned char *) malloc (sizeof (char) * 1);
  570.   if (data == NULL) {
  571.  
  572.     fprintf (stderr, "Sorry, out of memory!\n");
  573.     exit (1);
  574.     }
  575.   data[0] = (unsigned char) program;
  576.   add_packet ((unsigned long) Mf_currtime, program_chng, MIDI_EVENT, chan, data, (unsigned long) 1);
  577. }
  578.  
  579. /* ------------------------------------------------------------------------ */
  580.  
  581. /* mypitchbend : returns <int> with input variables:
  582.  * chan:
  583.  * msb:
  584.  * lsb:
  585.  */
  586. int mypitchbend (
  587.   int chan,
  588.   int msb,
  589.   int lsb)
  590. {
  591.   unsigned char *data;
  592.   data = (unsigned char *) malloc (sizeof (char) * 2);
  593.   if (data == NULL) {
  594.  
  595.     fprintf (stderr, "Sorry, out of memory!\n");
  596.     exit (1);
  597.     }
  598.   data[0] = (unsigned char) msb;
  599.   data[1] = (unsigned char) lsb;
  600.   add_packet ((unsigned long) Mf_currtime, pitch_wheel, MIDI_EVENT, chan, data, (unsigned long) 2);
  601. }
  602.  
  603. /* ------------------------------------------------------------------------ */
  604.  
  605. /* mysysex : returns <int> with input variables:
  606.  * len:
  607.  * msg:
  608.  */
  609. int mysysex (
  610.   int len,
  611.   char *msg)
  612. {
  613.   unsigned char *data;
  614.   int i;
  615.  
  616.   data = (unsigned char *) malloc ((unsigned) (sizeof (char) * len));
  617.   if (data == NULL) {
  618.  
  619.     fprintf (stderr, "Sorry, out of memory!\n");
  620.     exit (1);
  621.     }
  622.   for (i = 0; i < len; i++)
  623. data[i] = msg[i];
  624.   add_packet ((unsigned long) Mf_currtime, system_exclusive, MIDI_EVENT, 0, data, (unsigned long) len);
  625. }
  626.  
  627. /* ------------------------------------------------------------------------ */
  628.  
  629. /* myseqnum : returns <int> with input variables:
  630.  * num:
  631.  */
  632. int myseqnum (int num)
  633. {
  634.   unsigned char *data;
  635.   data = (unsigned char *) malloc (sizeof (char) * 1);
  636.   if (data == NULL) {
  637.  
  638.     fprintf (stderr, "Sorry, out of memory!\n");
  639.     exit (1);
  640.     }
  641.   data[0] = (unsigned char) num;
  642.   add_packet ((unsigned long) Mf_currtime, sequence_number, META_EVENT, 0, data, (unsigned long) 1);
  643. }
  644.  
  645. /* ------------------------------------------------------------------------ */
  646.  
  647. /* mytimesig : returns <int> with input variables:
  648.  * numer:
  649.  * denom:
  650.  * clocks:
  651.  * qnotes:
  652.  */
  653. int mytimesig (
  654.   int numer,
  655.   int denom,
  656.   int clocks,
  657.   int qnotes)
  658. {
  659.   unsigned char *data;
  660.  
  661.   data = (unsigned char *) malloc (sizeof (char) * 4);
  662.   if (data == NULL) {
  663.  
  664.     fprintf (stderr, "Sorry, out of memory!\n");
  665.     exit (1);
  666.     }
  667.   data[0] = numer;
  668.   data[1] = denom;
  669.   data[2] = clocks;
  670.   data[3] = qnotes;
  671.   add_packet ((unsigned long) Mf_currtime, time_signature, META_EVENT, 0, data, (unsigned long) 4);
  672. }
  673.  
  674. /* ------------------------------------------------------------------------ */
  675.  
  676. /* mykeysig : returns <int> with input variables:
  677.  * sharpflat:
  678.  * minor:
  679.  */
  680. int mykeysig (
  681.   int sharpflat,
  682.   int minor)
  683. {
  684.   unsigned char *data;
  685.  
  686.   data = (unsigned char *) malloc (sizeof (char) * 2);
  687.   if (data == NULL) {
  688.  
  689.     fprintf (stderr, "Sorry, out of memory!\n");
  690.     exit (1);
  691.     }
  692.   data[0] = sharpflat;
  693.   data[1] = minor;
  694.   add_packet ((unsigned long) Mf_currtime, key_signature, META_EVENT, 0, data, (unsigned long) 2);
  695. }
  696.  
  697. /* ------------------------------------------------------------------------ */
  698.  
  699. /* init_funcs : returns <int> with input variables:
  700.  * void:
  701.  */
  702. int init_funcs (void)
  703. {
  704.   sequence_start = 0L;
  705.   sequence_end = 0L;
  706.  
  707.   /* needed for reading */
  708.   Mf_getc = mygetc;
  709.   Mf_error = myerror;
  710.   Mf_header = myheader;
  711.   Mf_noteon = mynoteon;
  712.   Mf_noteoff = mynoteoff;
  713.   Mf_pressure = mypressure;
  714.   Mf_parameter = myparameter;
  715.   Mf_pitchbend = mypitchbend;
  716.   Mf_program = myprogram;
  717. //  Mf_chanpressure = mykeypressure;
  718.   Mf_sysex = mysysex;
  719.   Mf_metamisc = myvarlen;
  720.   Mf_seqspecific = myvarlen;
  721.   Mf_seqnum = myseqnum;
  722.   Mf_text = myvarlen;
  723.   Mf_timesig = mytimesig;
  724.   Mf_smpte = mysmpte;
  725.   Mf_tempo = mytempo;
  726.   Mf_keysig = mykeysig;
  727.  
  728.   /* needed for writing */
  729.   Mf_putc = myputc;
  730.   Mf_writetrack = mywritetrack;
  731. }
  732.  
  733. /* ------------------------------------------------------------------------ */
  734.  
  735.